package redis_ope

import (
	"context"
	"fmt"
	log "github.com/sirupsen/logrus"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

const (
	IFCONFIG_URL = "http://sign.antsxdp.com/cdn22/antscdn_master.php"
)

var (
	ctx          = context.Background()
	g_rdb_remote *redis.Client

	TASKSTREAM = ""
)

func initRedis() {
	var err error
	g_rdb_remote, err = connectToRedis()
	if err != nil {
		os.Exit(1)
	}
	log.Tracef(" init success")
}

// scan all data from redis which keys match r
func GetInitDataFromRedis(r string) ([]string, error) {
	//recursive get from redis scan
	data := make([]string, 0)
	var cursor uint64
	for true {
		dataArray, c, err := g_rdb_remote.Scan(ctx, cursor, r, 10000).Result()
		log.Tracef("getInitDataFromRedis cursor: %d, len: %d", c, len(dataArray))
		if err != nil {
			log.Error(err)
			break
		}

		//log.Tracef("get data from redis: %s", dataArray)
		if len(dataArray) > 0 {
			//log.Tracef("get data from redis: %s", dataArray)
			data = append(data, dataArray...)
			cursor = c
			log.Tracef("getInitDataFromRedis from redis: %d", len(data))
		}

		if len(dataArray) == 0 && c != 0 {
			cursor = c
			continue
		}

		if c == 0 {
			break
		}
	}

	if len(data) > 0 {
		return data, nil
	}

	return nil, fmt.Errorf("get slave data from redis failed")
}

func GetTaskFromRedis(stream_name string) chan []redis.XStream {
	var (
		TailId       = "$"
		task_channel = make(chan []redis.XStream, 1024)
	)

	TASKSTREAM = stream_name

	go func(chan []redis.XStream) {
		for {
			func() {
				defer func() {
					if err := recover(); err != nil {
						log.Error(err)
					}
				}()

				task, err := g_rdb_remote.XRead(ctx, &redis.XReadArgs{
					Streams: []string{TASKSTREAM, TailId},
					Block:   5 * time.Second,
				}).Result()
				if err != nil {
					return
				}

				if len(task) > 0 {
					messages := task[len(task)-1].Messages
					TailId = messages[len(messages)-1].ID

					task_channel <- task
				}

			}()
		}
	}(task_channel)

	return task_channel
}

func connectToRedis() (*redis.Client, error) {
	var err error
	g_conf, err := config.GetConf()
	if err != nil {
		log.Error(err)
		return nil, err
	} else {
		log.Trace("get config success: ", g_conf)
	}

	rdb := redis.NewClient(&redis.Options{
		Addr:        g_conf.RedisAddr,
		Password:    g_conf.RedisAuth, // no password set
		DB:          0,                // use default DB
		DialTimeout: 30 * time.Second,
		ReadTimeout: time.Minute,
	})
	_, err = rdb.Ping(ctx).Result()
	if err != nil {
		log.Error(err)
		return nil, err
	} else {
		log.Trace("connect to remote redis success")
		return rdb, nil
	}
}

func GetLocalAddrFromIfconfig() (string, error) {
	resp, err := http.Get(IFCONFIG_URL)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	data, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	result := strings.TrimSpace(string(data))
	con := strings.Split(result, "|")
	if len(con) == 0 {
		return "", fmt.Errorf("format error")
	}

	return con[0], nil
}

func Connect() {
	start := time.Now()
	initRedis()
	log.Tracef("connect to remote redis cost: %s", time.Since(start))

	for data := range GetTaskFromRedis("tcp_simple_firewall") {
		if len(data) == 0 {
			continue
		}

		log.Tracef("get data from redis: %++v", data)
	}
}
